#include "Tools.h"

void Tools::PrintStringToHex(const char* input, int length)
{
    for (int i = 0; i < length; i++) printf("%x ", input[i] & 0xff);
    printf("\n");
}

void Tools::PrintStringToHex(const uint8_t* input, int length)
{
    for (int i = 0; i < length; i++) printf("%x ", input[i] & 0xff);
    printf("\n");
}

std::string Tools::PrintIntToHex(int input)
{
    std::string res;
    int temp = input % 16; 
    if(temp < 10) res = (input % 16 + 48);
    else res = (input % 16 + 87);
    input /= 16;

    temp = input % 16; 
    if(temp < 10) res = (char)(input % 16 + 48) + res;
    else res = (char)(input % 16 + 87) + res;

    return res;
}

void Tools::htonll(double val, uint8_t* ret)
{
    memcpy(ret, &val, 8);
    if(NEED_CONVERT)
    {
        for (int i = 0; i < 4; i++)
        {
            char c = ret[i];
            ret[i] = ret[7 - i];
            ret[7 - i] = c;
        }
    }
}

void Tools::htonll(long val, uint8_t* ret)
{
    memcpy(ret, &val, 8);
    if(NEED_CONVERT)
    {
        for (int i = 0; i < 4; i++)
        {
            char c = ret[i];
            ret[i] = ret[7 - i];
            ret[7 - i] = c;
        }
    }
}

int Tools::SPSDecode(char* SPS, int& startIndex)
{
    int res = SPSDecodeU(SPS, startIndex);
    int charIndex = startIndex / 8;
    int bitIndex = startIndex % 8;
    char bitValue = (SPS[charIndex] >> (7 - bitIndex)) & 0x01;
    startIndex++;

    if(bitValue == 1) return -res;
    return res;
}

int Tools::SPSDecodeU(char* SPS, int& startIndex)
{
    int charIndex = startIndex / 8;
    int bitIndex = startIndex % 8;

    int length = 0;
    char bitValue = (SPS[charIndex] >> (7 - bitIndex)) & 0x01;
    while (bitValue == 0)
    {
        length++;
        bitIndex++;
        if(bitIndex == 8)
        {
            bitIndex = 0;
            charIndex++;
        }
        bitValue = (SPS[charIndex] >> (7 - bitIndex)) & 0x01;
    }
    
    int result = 0;
    for (int i = 0; i < length + 1; i++)
    {
        result = result * 2 + bitValue;

        bitIndex++;
        if(bitIndex == 8)
        {
            bitIndex = 0;
            charIndex++;
        }
        bitValue = (SPS[charIndex] >> (7 - bitIndex)) & 0x01;
    }
    
    startIndex = bitIndex + 8 * charIndex;
    return result - 1;
}

std::string Tools::ComputeMD5(const std::string& input)
{
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5_CTX ctx;
    MD5_Init(&ctx);
    MD5_Update(&ctx, input.c_str(), input.size());
    MD5_Final(digest, &ctx);
 
    char mdString[2*MD5_DIGEST_LENGTH + 1];
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
        sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
    }
    return std::string(mdString);
}

std::string Tools::EncodeBase64(const std::string &txt) {
    if (txt.empty()) {
        return "";
    }
    int size = AV_BASE64_SIZE(txt.size()) + 10;
    std::string ret;
    ret.resize(size);

    if (!av_base64_encode_l((char *) ret.data(), &size, (const uint8_t *) txt.data(), txt.size())) {
        return "";
    }
    ret.resize(size);
    return ret;
}

char* Tools::av_base64_encode_l(char *out, int *out_size, const uint8_t *in, int in_size) {
    static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    char *ret, *dst;
    unsigned i_bits = 0;
    int i_shift = 0;
    int bytes_remaining = in_size;

    if ((size_t)in_size >= UINT_MAX / 4 || *out_size < AV_BASE64_SIZE(in_size)) {
        return nullptr;
    }
    ret = dst = out;
    while (bytes_remaining) {
        i_bits = (i_bits << 8) + *in++;
        bytes_remaining--;
        i_shift += 8;

        do {
            *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];
            i_shift -= 6;
        } while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0));
    }
    while ((dst - ret) & 3)
        *dst++ = '=';
    *dst = '\0';

    *out_size = dst - out;
    return ret;
}

bool Tools::WriteFile(FILE* flie, int socketFd, uint8_t* buffer, size_t length, std::string errorMsg)
{
    if(socketFd == -1 || send(socketFd, buffer, length, MSG_NOSIGNAL) == -1)
    {
        std::cout << "FLV客户端套接字写入失败，连接关闭" << std::endl;
        return false;
    }


    if(flie)
    { 
        if (fwrite(buffer, 1, length, flie) != length)
        {
            std::cout << errorMsg << std::endl;
            return false;
        }
    }
    return true;
}

bool Tools::WriteFile(FILE* flie, int socketFd, char* buffer, size_t length, std::string errorMsg)
{
    if(socketFd == -1 || send(socketFd, buffer, length, MSG_NOSIGNAL) == -1)
    {
        std::cout << "FLV客户端套接字写入失败，连接关闭" << std::endl;
        return false;
    }


    if(flie)
    { 
        if (fwrite(buffer, 1, length, flie) != length)
        {
            std::cout << errorMsg << std::endl;
            return false;
        }
    }
    return true;
}

bool Tools::WriteFile(FILE* flie, int socketFd, int* buffer, size_t length, std::string errorMsg)
{
    if(socketFd == -1 || send(socketFd, buffer, length, MSG_NOSIGNAL) == -1)
    {
        std::cout << "FLV客户端套接字写入失败，连接关闭" << std::endl;
        return false;
    }

    if(flie)
    { 
        if (fwrite(buffer, 1, length, flie) != length)
        {
            std::cout << errorMsg << std::endl;
            return false;
        }
    }
    return true;
}
